<?php
abstract class Core_Model_Controller {
	
	protected $_layout = null;

	abstract public function getArea();

	public function dispatch($action) {
		try {
			$actionMethodName = $this->_getActionMethodName($action);
			if (!is_callable(array($this, $actionMethodName)))
				throw new Exception("Controller action: '$action' not existed.");

			$this->_beforeDispatch();
			
			Mag::registry('controller', $this);
			$this->$actionMethodName();

			$this->_afterDispatch();
		} catch (Core_Model_Exception_Redirect $e) {
			Mag::getResponse()->setRedirect($e->getRedirectUrl());

		} catch (Core_Model_Exception_Forward $e) {
			$req = Mag::getRequest();
			
			if ($e->getFrontName())
				$req->setFrontName($e->getFrontName());
			
			if ($e->getControllerName())
				$req->setControllerName($e->getControllerName());
			
			if ($e->getActionName())
				$req->setActionName($e->getActionName());

			if ($e->getRouteParams())
				$req->setParams($e->getRouteParams());

			$req->setDispatched(false);
		}
		return $this;
	}

	public function hasAction($action) {
		return is_callable(array($this, $this->_getActionMethodName($action)));
	}

	public function getActionHandle() {
		$req = Mag::getRequest();
		return strtolower($req->getFrontName() . '_' . $req->getControllerName() . '_' . $req->getActionName());
	}
	
	/**
	 * Retrieve action method name
	 *
	 * @param string $action
	 * @return string
	 */
	protected function _getActionMethodName($action) {
		return $action . 'Action';
	}

	protected function _forward($action, $controller = null, $frontName = null, $params = null) {
		throw new Core_Model_Exception_Forward($action, $controller, $frontName, $params);
	}

	protected function _redirect($routePath = null, $routeParams = null) {
		$url = Mag::getUrl($routePath, $routeParams);
		throw new Core_Model_Exception_Redirect($url);
	}

	protected function _beforeDispatch() {}
	
	protected function _afterDispatch() {}

	protected function _loadLayout() {
		// sort layout files
		$layoutConfigPath = $this->getArea()->getName() . '/layout';
		Mag::getConfig()->sortConfig($layoutConfigPath, 'order');

		// load layout xml files
		$layouts = Mag::getConfig()->get($layoutConfigPath);
		if (!$layouts) return;
		foreach($layouts as $layout) {
			$fileName = $this->getArea()->getCurrentTheme()->getLayoutFilename($layout['file']);
			if (!$fileName) continue;
			$this->getLayout()->addXml(file_get_contents($fileName));
		}

		// add action handles
		$this->getLayout()->addHandle($this->getActionHandle());
		$this->getLayout()->load();
		return $this;
	}

	protected function _renderLayout() {
		$output = $this->getLayout()->getOutput();
		Mag::getResponse()->appendBody($output);
		return $this;
	}
	
	public function getLayout() {
		if ($this->_layout === null)
			$this->_layout = Mag::object('Core_Model_Layout');
		return $this->_layout;
	}
	
}